﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NextInventory.Data;
using NextInventory.Model.Inventory;

namespace NextInventory.Business.EntityRepositories
{
    public interface IInventoryRepository : IBaseRepository
    {

        #region Category

        List<CategoryModel> GetAllCategories();
        CategoryModel GetCategoryByID(int Id);
        List<CategoryModel> SearchCategories(CategoryModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords);
        List<CategoryModel> GetCategoryByModelID(int Id);
        string CategoryNameAvailability(string CategoryName);

        bool AddCategory(CategoryModel model, out string message);
        bool UpdateCategory(CategoryModel model, out string message);
        bool DeleteCategory(int Id, out string message);

        #endregion Category

        #region Model

        ModelModel GetProductModelByID(int Id);
        List<ModelModel> GetAllModels();
        List<ModelModel> SearchModels(ModelModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords);
        List<ModelModel> GetProductModelByModelID(int Id);

        bool AddProductModel(ModelModel model, out string message);
        bool UpdateProductModel(ModelModel model, out string message);
        bool DeleteProductModel(int Id);

        #endregion Model

        #region Product

        ProductsModel GetProductByID(int Id);
        List<ProductsModel> SearchProducts(ProductsModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords);
        List<ProductsModel> GetProductsByModelID(int Id);

        bool AddProduct(ProductsModel model);
        bool UpdateProduct(ProductsModel model);
        bool DeleteProduct(int Id);

        #endregion Product
    }

    public class InventoryRepository : BaseRepository, IInventoryRepository
    {
        NextInventoryContext context = new NextInventoryContext();

        #region Category

        public List<CategoryModel> SearchCategories(CategoryModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords)
        {
            var q = (from c in context.Categories
                     orderby c.Name
                     select new CategoryModel
                     {
                         CategoryId = c.CategoryId,
                         Name = c.Name,
                         Description = c.Description
                     }
                );
            if (!string.IsNullOrEmpty(filter.Name))
            {
                q = q.Where(c => c.Name.ToLower().Contains(filter.Name.ToLower()));
            }
            if (!string.IsNullOrEmpty(filter.Description))
            {
                q = q.Where(c => c.Description.ToLower().Contains(filter.Description.ToLower()));
            }
            switch (sortColumn)
            {
                case "Name":
                    q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Name) : q.OrderBy(c => c.Name);
                    break;
                case "Description":
                    q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Description) : q.OrderBy(c => c.Description);
                    break;
                default:
                    break;
            }
            totalRecords = q.Count();
            return q.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public CategoryModel GetCategoryByID(int Id)
        {
            return (from c in context.Categories
                    select new CategoryModel
                    {
                        CategoryId = c.CategoryId,
                        Name = c.Name,
                        Description = c.Description
                    }).FirstOrDefault(o => o.CategoryId == Id);

        }

        public List<CategoryModel> GetAllCategories()
        {
            List<CategoryModel> model = new List<CategoryModel>();
            model = (from m in context.Categories
                     select new CategoryModel
                     {
                         CategoryId = m.CategoryId,
                         Name = m.Name,
                         Description = m.Description
                     }
                     ).ToList();
            return model;
        }

        public string CategoryNameAvailability(string CategoryName)
        {
            string categoryExist;
            try
            {
                var category = _Contaxt.Categories.FirstOrDefault(o => o.Name == CategoryName);
                if (category == null)
                {
                    categoryExist = "available";
                }
                else
                {
                    categoryExist = "taken";
                }
            }
            catch (Exception ex)
            {
                categoryExist = "error";
            }
            return categoryExist;
        }

        public List<CategoryModel> GetCategoryByModelID(int Id)
        {
            throw new NotImplementedException();
        }

        public bool AddCategory(CategoryModel model, out string message)
        {
            if (string.IsNullOrEmpty(model.Name))
            {
                message = "Category name is required.";
                return false;
            }
            Category category = new Category()
            {
                Name = model.Name,
                Description = model.Description
            };

            context.Categories.Add(category);
            context.SaveChanges();

            if (category.CategoryId > 0)
            {
                message = "Category successfull inserted.";
                return true;
            }
            else
            {
                message = "Error occured during saving category.";
                return false;
            }
        }

        public bool UpdateCategory(CategoryModel model, out string message)
        {
            Category category = context.Categories.FirstOrDefault(c => c.CategoryId == model.CategoryId);
            category.Name = model.Name;
            category.Description = model.Description;
            context.SaveChanges();
            message = "Category updated successfully.";
            return true;

        }

        public bool DeleteCategory(int Id, out string message)
        {
            Category category = context.Categories.FirstOrDefault(o => o.CategoryId == Id);
            context.Categories.Remove(category);
            context.SaveChanges();
            message = "Deleted successfully.";
            return true;
        }

        #endregion Category

        #region Model

        public ModelModel GetProductModelByID(int Id)
        {
            return (from m in context.ProductModels
                    select new ModelModel
                    {
                        ModelId = m.ModelId,
                        Name = m.Name,
                        Description = m.Description
                    }).FirstOrDefault(m => m.ModelId == Id);
        }

        public List<ModelModel> GetAllModels()
        {
            List<ModelModel> model = new List<ModelModel>();
            model = (from m in context.ProductModels
                     select new ModelModel
                     {
                         ModelId = m.ModelId,
                         Name = m.Name,
                         Description = m.Description,
                         IsActive = m.IsActive,
                         CreatedBy = m.CreatedBy,
                         CreatedDate = m.CreatedDate,
                         UpdatedBy = m.UpdatedBy,
                         UpdatedDate = m.UpdatedDate
                     }).ToList();
            return model;
        }

        public List<ModelModel> SearchModels(ModelModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords)
        {
            var q = (from c in context.ProductModels
                     orderby c.Name
                     select new ModelModel
                     {
                         ModelId = c.ModelId,
                         Name = c.Name,
                         Description = c.Description
                     }
                 );
            if (!string.IsNullOrEmpty(filter.Name))
            {
                q = q.Where(c => c.Name.ToLower().Contains(filter.Name.ToLower()));
            }
            if (!string.IsNullOrEmpty(filter.Description))
            {
                q = q.Where(c => c.Description.ToLower().Contains(filter.Description.ToLower()));
            }
            switch (sortColumn)
            {
                case "Name":
                    q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Name) : q.OrderBy(c => c.Name);
                    break;
                case "Description":
                    q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Description) : q.OrderBy(c => c.Description);
                    break;
                default:
                    break;
            }
            totalRecords = q.Count();
            return q.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public List<ModelModel> GetProductModelByModelID(int Id)
        {
            throw new NotImplementedException();
        }

        public bool AddProductModel(ModelModel model, out string message)
        {
            if (string.IsNullOrEmpty(model.Name))
            {
                message = "Name is required.";
                return false;
            }

            ProductModel productModel = new ProductModel()
            {
                Name = model.Name,
                Description = model.Description,
                CreatedDate = DateTime.Now,
                UpdatedDate = DateTime.Now,
                CreatedBy = 1,
                UpdatedBy = 1
            };

            context.ProductModels.Add(productModel);
            context.SaveChanges();

            if (productModel.ModelId > 0)
            {
                message = "Product model successfully inserted.";
                return true;
            }
            else
            {
                message = "Error occured saving product model.";
                return false;
            }
        }

        public bool UpdateProductModel(ModelModel model, out string message)
        {
            ProductModel product = context.ProductModels.FirstOrDefault(m => m.ModelId == model.ModelId);
            product.Name = model.Name;
            product.Description = model.Description;
            context.SaveChanges();
            message = "Product model updated successfully.";
            return true;
        }

        public bool DeleteProductModel(int Id)
        {
            ProductModel model = context.ProductModels.FirstOrDefault(o => o.ModelId == Id);
            context.ProductModels.Remove(model);
            context.SaveChanges();
            return true;
        }

        #endregion Model

        #region Product

        public List<ProductsModel> SearchProducts(ProductsModel filter, string sortColumn, string sortOrder, int pageSize, int pageIndex, out int totalRecords)
        {
            try
            {

                var q = from p in context.Products
                        orderby p.Name
                        select new ProductsModel
                        {
                            ID = p.ProductId,
                            Name = p.Name,
                            Description = p.Description,
                            ExpiryDate = p.ExpiryDate,
                            PurchaseDate = p.PurchaseDate,
                            PurchaseRate = p.PurchaseRate,
                            MenuFacturingDate = p.MenuFacturingDate,
                            OpeningQty = p.OpeningQty,
                            OpeningValue = p.OpeningValue,
                            SaleRate = p.SaleRate,
                            CategoryId = p.CategoryId,
                            ModelId = p.ModelId,
                            MenufacturerId = p.MenufacturerId,
                            CreatedBy = p.CreatedBy,
                            CreatedDate = p.CreatedDate,
                            UpdatedBy = p.UpdatedBy,
                            UpdatedDate = p.UpdatedDate
                        };
                if (!string.IsNullOrEmpty(filter.Name))
                {
                    q = q.Where(c => c.Name.ToLower().Contains(filter.Name.ToLower()));
                }
                if (!string.IsNullOrEmpty(filter.Description))
                {
                    q = q.Where(c => c.Description.ToLower().Contains(filter.Description.ToLower()));
                }
                if (!string.IsNullOrEmpty(filter.ExpiryDate.ToString()))
                {
                    q = q.Where(c => c.ExpiryDate.Equals(filter.ExpiryDate));
                }
                if (string.IsNullOrEmpty(filter.PurchaseDate.ToString()))
                {
                    q = q.Where(c => c.PurchaseDate.Equals(filter.PurchaseDate));
                }

                switch (sortColumn)
                {
                    case "ID":
                        q = (sortOrder == "desc") ? q.OrderByDescending(c => c.ID) : q.OrderBy(c => c.ID);
                        break;
                    case "Name":
                        q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Name) : q.OrderBy(c => c.Name);
                        break;
                    case "Description":
                        q = (sortOrder == "desc") ? q.OrderByDescending(c => c.Description) : q.OrderBy(c => c.Description);
                        break;
                    case "ExpiryDate":
                        q = (sortOrder == "desc") ? q.OrderByDescending(c => c.ExpiryDate) : q.OrderBy(c => c.ExpiryDate);
                        break;
                    case "PurchaseDate":
                        q = (sortOrder == "desc") ? q.OrderByDescending(c => c.PurchaseDate) : q.OrderBy(c => c.PurchaseDate);
                        break;
                    default:
                        break;
                }
                totalRecords = q.Count();
                return q.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            catch (Exception)
            {

                throw;
            }
        }

        public ProductsModel GetProductByID(int Id)
        {
            return (from p in context.Products
                    select new ProductsModel
                   {
                       ID = p.ProductId,
                       Name = p.Name,
                       Description = p.Description,
                       ExpiryDate = p.ExpiryDate,
                       MenuFacturingDate = p.MenuFacturingDate,
                       PurchaseDate = p.PurchaseDate,
                       OpeningQty = p.OpeningQty,
                       OpeningValue = p.OpeningValue,
                       PurchaseRate = p.PurchaseRate,
                       SaleRate = p.SaleRate,
                       CategoryId = p.CategoryId,
                       ModelId = p.ModelId,
                       MenufacturerId = p.MenufacturerId
                   }).FirstOrDefault(p => p.ID == Id);
        }

        public List<ProductsModel> GetProductsByModelID(int Id)
        {
            throw new NotImplementedException();
        }

        public bool AddProduct(ProductsModel model)
        {
            try
            {
                Product product = new Product()
                {                   
                    Name = model.Name,
                    Description = model.Description,
                    ExpiryDate = model.ExpiryDate,
                    PurchaseDate = model.PurchaseDate,
                    MenuFacturingDate = model.MenuFacturingDate,
                    OpeningQty = model.OpeningQty,
                    OpeningValue = model.OpeningValue,
                    PurchaseRate = model.PurchaseRate,
                    SaleRate = model.SaleRate,
                    CategoryId = model.CategoryId,
                    MenufacturerId = model.MenufacturerId,
                    ModelId = model.ModelId,
                    CreatedDate = DateTime.Now,
                    UpdatedDate = DateTime.Now

                };
                context.Products.Add(product);
                context.SaveChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
                throw;
            }
        }

        public bool UpdateProduct(ProductsModel model)
        {
            try
            {
                Product product = context.Products.FirstOrDefault(p => p.ProductId == model.ID);
                product.Name = model.Name;
                product.Description = model.Description;
                product.ExpiryDate = model.ExpiryDate;
                product.MenuFacturingDate = model.MenuFacturingDate;
                product.PurchaseDate = model.PurchaseDate;
                product.OpeningQty = model.OpeningQty;
                product.OpeningValue = model.OpeningValue;
                product.PurchaseRate = model.PurchaseRate;
                product.SaleRate = model.SaleRate;
                product.CategoryId = model.CategoryId;
                product.MenufacturerId = model.MenufacturerId;
                product.ModelId = model.ModelId;
                product.UpdatedDate = DateTime.Now;
                context.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw ex;
            }

        }

        public bool DeleteProduct(int Id)
        {
            try
            {
                Product product = context.Products.FirstOrDefault(p => p.ProductId == Id);
                context.Products.Remove(product);
                context.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw ex;
            }
        }

        #endregion Product

    }
}
